package cn.tannn.ops.customer.controller;


import cn.tannn.jdevelops.annotations.web.authentication.ApiMapping;
import cn.tannn.jdevelops.annotations.web.constant.PlatformConstant;
import cn.tannn.jdevelops.annotations.web.mapping.PathRestController;
import cn.tannn.jdevelops.exception.built.UserException;
import cn.tannn.jdevelops.jwt.redis.entity.StorageUserRole;
import cn.tannn.jdevelops.jwt.redis.entity.StorageUserState;
import cn.tannn.jdevelops.jwt.redis.entity.sign.RedisSignEntity;
import cn.tannn.jdevelops.jwt.redis.service.RedisLoginService;
import cn.tannn.jdevelops.jwt.standalone.pojo.TokenSign;
import cn.tannn.jdevelops.jwt.standalone.util.JwtWebUtil;
import cn.tannn.jdevelops.redis.limit.LoginLimitService;
import cn.tannn.jdevelops.result.response.ResultVO;
import cn.tannn.jdevelops.utils.jwt.module.LoginJwtExtendInfo;
import cn.tannn.jdevelops.utils.jwt.module.SignEntity;
import cn.tannn.ops.customer.constant.LoginType;
import cn.tannn.ops.customer.constant.RoleDef;
import cn.tannn.ops.customer.controller.dto.LoginAttach;
import cn.tannn.ops.customer.controller.dto.LoginPassword;
import cn.tannn.ops.customer.controller.vo.LoginVO;
import cn.tannn.ops.customer.entity.Customer;
import cn.tannn.ops.customer.service.CustomerService;
import cn.tannn.ops.customer.service.RoleCustomerService;
import cn.tannn.ops.logs.controller.dto.LoginLogRecord;
import cn.tannn.ops.logs.service.LoginLogService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.extensions.Extension;
import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.Collections;
import java.util.List;




/**
 * 登录管理
 *
 * @author tnnn
 */
@Tag(name = "登录管理", description = "登录管理",
        extensions = {
                @Extension(properties = {
                        @ExtensionProperty(name = "x-order", value = "1", parseValue = true)
                })
        })
@PathRestController
@RequiredArgsConstructor
@Slf4j
public class LoginController {

    private final RedisLoginService redisLoginService;
    private final CustomerService customerService;
    private final RoleCustomerService roleCustomerService;
    private final LoginLogService loginLogService;
    private final LoginLimitService loginLimitService;


    /**
     * 登录-管理端登录
     *
     * @param login LoginDTO
     * @return ResultVO
     */
    @Operation(summary = "账户密码登录-admin")
    @ApiMapping(value = "/login", checkToken = false, method = RequestMethod.POST)
    public ResultVO<LoginVO> login(@RequestBody @Valid LoginPassword login, HttpServletRequest request) {
        // 第一步 先验证
        loginLimitService.verify(login.getLoginName(), true);
        try {
            // 第二步 登录验证
            // 日志相关的埋点后续优化
            Customer customer = customerService.authenticateUser(login, new LoginAttach(request, LoginType.ADMIN_ACCOUNT_PASSWORD));
            //  角色 -
            List<String> userRole = roleCustomerService.getRoleCodeByUserId(customer.getId());
            if (userRole == null || userRole.isEmpty() || !userRole.contains(RoleDef.USER_ADMIN)) {
                throw new UserException(405, "非管理员非法登录管理后台");
            }
            String sign = loginUserSign(customer, request, Collections.singletonList(PlatformConstant.WEB_ADMIN), LoginType.ADMIN_ACCOUNT_PASSWORD);
            return ResultVO.success("登录成功", new LoginVO(sign));
        } catch (Exception e) {
            // 第三步 记录次数
            loginLimitService.limit(login.getLoginName());
            throw e;
        }

    }


    /**
     * 登录-管理端登录
     *
     * @param login LoginDTO
     * @return ResultVO
     */
    @Operation(summary = "账户密码登录-利用端登录")
    @ApiMapping(value = "/login/web", checkToken = false, method = RequestMethod.POST)
    public ResultVO<LoginVO> loginWeb(@RequestBody @Valid LoginPassword login, HttpServletRequest request) {
        // 第一步 先验证
//        loginLimitService.verify(login.getLoginName(), true);
        try {
            // 第二步 登录验证
            // 日志相关的埋点后续优化
            Customer customer = customerService.authenticateUser(login, new LoginAttach(request, LoginType.WEB_ACCOUNT_PASSWORD));
            String sign = loginUserSign(customer, request, Collections.singletonList(PlatformConstant.WEB_H5), LoginType.WEB_ACCOUNT_PASSWORD);
            return ResultVO.success("登录成功", new LoginVO(sign));
        } catch (Exception e) {
            // 第三步 记录次数
//            loginLimitService.limit(login.getLoginName());
            throw e;
        }

    }


    /**
     * 退出
     *
     * @param request HttpServletRequest
     * @return 退出
     */
    @Operation(summary = "退出")
    @GetMapping("/logout")
    public ResultVO<String> logout(HttpServletRequest request) {
        redisLoginService.loginOut(request);
        return ResultVO.successMessage("成功退出");
    }


    @Operation(summary = "解析当前登录者的token")
    @ApiMapping(value = "parse")
    public ResultVO<SignEntity<String>> parseToken(HttpServletRequest request) {
        return ResultVO.success(JwtWebUtil.getTokenBySignEntity(request));
    }


    /**
     * 构造登录信息
     *
     * @param customer  Customer
     * @param request   HttpServletRequest
     * @param platform  PlatformConstant
     * @param loginType 登录类型
     * @return token
     */
    private String loginUserSign(Customer customer, HttpServletRequest request, List<String> platform, LoginType loginType) {
        // PS 非账号密码没有loginName 所以此处全用 no

        RedisSignEntity<LoginJwtExtendInfo> redisSignEntity = new RedisSignEntity<>(
                customer.getLoginName(),
                platform,
                false,
                false,
                new StorageUserState(
                        customer.getLoginName(),
                        customer.getStatus(),
                        customer.getStatusMark())
        );
        //  角色 -
        List<String> userRole = roleCustomerService.getRoleCodeByUserId(customer.getId());
        redisSignEntity.setUserRole(
                new StorageUserRole(
                        customer.getLoginName(),
                        userRole,
                        Collections.emptyList()));
        // 拓展信息
        LoginJwtExtendInfo<String> loginJwtExtendInfo = new LoginJwtExtendInfo<>();
        loginJwtExtendInfo.setUserId(customer.getId() + "");
        loginJwtExtendInfo.setUserNo(customer.getId() + "");
        loginJwtExtendInfo.setUserName(customer.getName());
        redisSignEntity.setMap(loginJwtExtendInfo);

        // todo 后面在优化
        LoginLogRecord logRecord = new LoginLogRecord();
        logRecord.setCustomer(customer);
        logRecord.setRequest(request);
        logRecord.setType(loginType.getDescription());
        try {
            TokenSign login = redisLoginService.login(redisSignEntity);
            logRecord.setToken(login.getSign());
            logRecord.setStatus(1);
            logRecord.setDescription(login.getDescription());
            loginLogService.recordLog(logRecord);
            return login.getSign();
        } catch (Exception e) {
            String message = e.getMessage();
            logRecord.setDescription(message.length() > 100 ? message.substring(0, 99) : message);
            logRecord.setStatus(0);
            loginLogService.recordLog(logRecord);
            throw e;
        }
    }


}
